/* -------------------------------------------------------------------------- *
   TestWinUnit - Maria Blees (maria.blees@microsoft.com)

   File: StructuredExceptionsTest.cpp

   These tests can only be verified by inspection.  They are just a sanity
   check to make sure that StructuredExceptions::GetDescription returns
   something reasonable for known and unknown cases.

   The expected known cases are the ones on the list at
   http://msdn2.microsoft.com/en-us/library/aa363082.aspx .
 * -------------------------------------------------------------------------- */

#include "WinUnit.h"

#include "StructuredExceptions.h"
#include <windows.h>

using namespace WinUnitLib;

namespace
{
    struct ExceptionType
    {
        DWORD Code;
        const TCHAR* Name;
    };
}

#pragma warning(push)
// This warning occurs because we're not using any WIN_ASSERT* macros in these
// tests and therefore don't have the possibility of throwing an exception.
// This is by design, thus the disabling of the warning.
#pragma warning(disable:4702)

BEGIN_TEST(StructuredExceptionsGetDescriptionShouldReturnSensibleDescriptionForKnownCases)
{
    ExceptionType knownExceptionTypes[] = {
        { EXCEPTION_ACCESS_VIOLATION, _T("EXCEPTION_ACCESS_VIOLATION") },
        { EXCEPTION_ARRAY_BOUNDS_EXCEEDED, _T("EXCEPTION_ARRAY_BOUNDS_EXCEEDED") },
        { EXCEPTION_BREAKPOINT, _T("EXCEPTION_BREAKPOINT") },
        { EXCEPTION_DATATYPE_MISALIGNMENT, _T("EXCEPTION_DATATYPE_MISALIGNMENT") },
        { EXCEPTION_FLT_DENORMAL_OPERAND, _T("EXCEPTION_FLT_DENORMAL_OPERAND") },
        { EXCEPTION_FLT_DIVIDE_BY_ZERO, _T("EXCEPTION_FLT_DIVIDE_BY_ZERO") },
        { EXCEPTION_FLT_INEXACT_RESULT, _T("EXCEPTION_FLT_INEXACT_RESULT") },
        { EXCEPTION_FLT_INVALID_OPERATION, _T("EXCEPTION_FLT_INVALID_OPERATION") },
        { EXCEPTION_FLT_OVERFLOW, _T("EXCEPTION_FLT_OVERFLOW") },
        { EXCEPTION_FLT_STACK_CHECK, _T("EXCEPTION_FLT_STACK_CHECK") },
        { EXCEPTION_FLT_UNDERFLOW, _T("EXCEPTION_FLT_UNDERFLOW") },
        { EXCEPTION_ILLEGAL_INSTRUCTION, _T("EXCEPTION_ILLEGAL_INSTRUCTION") },
        { EXCEPTION_IN_PAGE_ERROR, _T("EXCEPTION_IN_PAGE_ERROR") },
        { EXCEPTION_INT_DIVIDE_BY_ZERO, _T("EXCEPTION_INT_DIVIDE_BY_ZERO") },
        { EXCEPTION_INT_OVERFLOW, _T("EXCEPTION_INT_OVERFLOW") },
        { EXCEPTION_INVALID_DISPOSITION, _T("EXCEPTION_INVALID_DISPOSITION") },
        { EXCEPTION_NONCONTINUABLE_EXCEPTION, _T("EXCEPTION_NONCONTINUABLE_EXCEPTION") },
        { EXCEPTION_PRIV_INSTRUCTION, _T("EXCEPTION_PRIV_INSTRUCTION") },
        { EXCEPTION_SINGLE_STEP, _T("EXCEPTION_SINGLE_STEP") },
        { EXCEPTION_STACK_OVERFLOW, _T("EXCEPTION_STACK_OVERFLOW") }
    };

    for (int i = 0; i < ARRAYSIZE(knownExceptionTypes); i++)
    {
        ExceptionType exceptionType = knownExceptionTypes[i];
        WIN_TRACE(_T("INFO: Next line should contain description for exception type %s.\n"), exceptionType.Name);
        WIN_TRACE(L"OUTPUT: %s\n", StructuredExceptions::GetDescription(exceptionType.Code));
    }
}
END_TEST

BEGIN_TEST(StructuredExceptionsGetDescriptionShouldReturnSensibleDescriptionForUnknownCases)
{
    DWORD unknownExceptionTypes[] = {
        EXCEPTION_GUARD_PAGE,
        0xFFFFFFFF
    };

    for (int i = 0; i < ARRAYSIZE(unknownExceptionTypes); i++)
    {
        WIN_TRACE(_T("INFO: Next line should contain a description for an unknown type.\n"));
        WIN_TRACE(L"OUTPUT: %s\n", StructuredExceptions::GetDescription(
            unknownExceptionTypes[i]));
    }
}
END_TEST

#pragma warning(pop)
